home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / gnu / gas / gassrc04.zoo / atof-generic.c < prev    next >
C/C++ Source or Header  |  1991-01-24  |  17KB  |  527 lines

  1. /* atof_generic.c - turn a string of digits into a Flonum
  2.    Copyright (C) 1987 Free Software Foundation, Inc.
  3.  
  4. This file is part of GAS, the GNU Assembler.
  5.  
  6. GAS is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 1, or (at your option)
  9. any later version.
  10.  
  11. GAS is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GAS; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. #include <ctype.h>
  21. #include "flonum.h"
  22. #ifdef __GNUC__
  23. #define alloca __builtin_alloca
  24. #else
  25. #ifdef sparc
  26. #include <alloca.h>
  27. #endif
  28. #endif
  29.  
  30. #ifdef USG
  31. #define bzero(s,n) memset(s,0,n)
  32. #define index strchr
  33. #endif
  34.  
  35. #define    FALSE (0)
  36. #define TRUE  (1)
  37.  
  38. char *index();
  39.  
  40. /***********************************************************************\
  41. *                                    *
  42. *    Given a string of decimal digits , with optional decimal    *
  43. *    mark and optional decimal exponent (place value) of the        *
  44. *    lowest_order decimal digit: produce a floating point        *
  45. *    number. The number is 'generic' floating point: our        *
  46. *    caller will encode it for a specific machine architecture.    *
  47. *                                    *
  48. *    Assumptions                            *
  49. *        uses base (radix) 2                    *
  50. *        this machine uses 2's complement binary integers    *
  51. *        target flonums use "      "         "       "        *
  52. *        target flonums exponents fit in a long int        *
  53. *                                    *
  54. \***********************************************************************/
  55.  
  56. /*
  57.  
  58.             Syntax:
  59.  
  60. <flonum>        ::=    <optional-sign> <decimal-number> <optional-exponent>
  61. <optional-sign>        ::=    '+' | '-' | {empty}
  62. <decimal-number>    ::=      <integer>
  63.                 | <integer> <radix-character> 
  64.                 | <integer> <radix-character> <integer> 
  65.                 |        <radix-character> <integer>
  66. <optional-exponent>    ::=    {empty} | <exponent-character> <optional-sign> <integer> 
  67. <integer>        ::=    <digit> | <digit> <integer>
  68. <digit>            ::=    '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
  69. <exponent-character>    ::=    {one character from "string_of_decimal_exponent_marks"}
  70. <radix-character>    ::=    {one character from "string_of_decimal_marks"}
  71.  
  72. */
  73.  
  74. int                /* 0 if OK */
  75.  
  76. atof_generic (
  77.     address_of_string_pointer, /* return pointer to just AFTER number we read. */
  78.     string_of_decimal_marks, /* At most one per number. */
  79.     string_of_decimal_exponent_marks,
  80.     address_of_generic_floating_point_number)
  81.  
  82.      char * *        address_of_string_pointer;
  83.      const char *    string_of_decimal_marks;
  84.      const char *    string_of_decimal_exponent_marks;
  85.      FLONUM_TYPE *    address_of_generic_floating_point_number;
  86.  
  87. {
  88.  
  89.   int            return_value; /* 0 means OK. */
  90.   char *        first_digit;
  91.   /* char *        last_digit; JF unused */
  92.   int            number_of_digits_before_decimal;
  93.   int            number_of_digits_after_decimal;
  94.   long int        decimal_exponent;
  95.   int            number_of_digits_available;
  96.   char            digits_sign_char;
  97.  
  98.   {
  99.     /*
  100.      * Scan the input string, abstracting (1)digits (2)decimal mark (3) exponent.
  101.      * It would be simpler to modify the string, but we don't; just to be nice
  102.      * to caller.
  103.      * We need to know how many digits we have, so we can allocate space for
  104.      * the digits' value.
  105.      */
  106.  
  107.     char *        p;
  108.     char        c;
  109.     int            seen_significant_digit;
  110.  
  111.     first_digit = * address_of_string_pointer;
  112.     c= *first_digit;
  113.     if (c=='-' || c=='+')
  114.       {
  115.     digits_sign_char = c;
  116.         first_digit ++;
  117.       }
  118.     else
  119.     digits_sign_char = '+';
  120.  
  121.     if(   (first_digit[0]=='n' || first_digit[0]=='N')
  122.        && (first_digit[1]=='a' || first_digit[1]=='A')
  123.        && (first_digit[2]=='n' || first_digit[2]=='N')) {
  124.       address_of_generic_floating_point_number->sign=0;
  125.       address_of_generic_floating_point_number->exponent=0;
  126.       address_of_generic_floating_point_number->leader=address_of_generic_floating_point_number->low;
  127.       (*address_of_string_pointer)=first_digit+3;
  128.       return 0;
  129.     }
  130.     if(   (first_digit[0]=='i' || first_digit[0]=='I') 
  131.        && (first_digit[1]=='n' || first_digit[1]=='N')
  132.        && (first_digit[2]=='f' || first_digit[2]=='F')) {
  133.       address_of_generic_floating_point_number->sign= digits_sign_char=='+' ? 'P' : 'N';
  134.       address_of_generic_floating_point_number->exponent=0;
  135.       address_of_generic_floating_point_number->leader=address_of_generic_floating_point_number->low;
  136.       if(   (first_digit[3]=='i' || first_digit[3]=='I')
  137.          && (first_digit[4]=='n' || first_digit[4]=='N')
  138.      && (first_digit[5]=='i' || first_digit[5]=='I')
  139.      && (first_digit[6]=='t' || first_digit[6]=='T')
  140.      && (first_digit[7]=='y' || first_digit[7]=='Y'))
  141.       (*address_of_string_pointer)=first_digit+8;
  142.       else
  143.       (*address_of_string_pointer)=first_digit+3;
  144.       return 0;
  145.     }
  146.  
  147.     number_of_digits_before_decimal = 0;
  148.     number_of_digits_after_decimal = 0;
  149.     decimal_exponent = 0;
  150.     seen_significant_digit = FALSE;
  151.     for (p = first_digit;
  152.      (c = * p)
  153.      && (!c || ! index (string_of_decimal_marks,          c) )
  154.      && (!c || ! index (string_of_decimal_exponent_marks, c) );
  155.      p ++)
  156.       {
  157.     if (isdigit(c))
  158.       {
  159.         if (seen_significant_digit || c > '0')
  160.           {
  161.         number_of_digits_before_decimal ++;
  162.         seen_significant_digit = TRUE;
  163.           }
  164.         else
  165.           {
  166.             first_digit++;
  167.           }
  168.       }
  169.     else
  170.       {
  171.         break;        /* p -> char after pre-decimal digits. */
  172.       }
  173.       }                /* For each digit before decimal mark. */
  174.     if (c && index (string_of_decimal_marks, c))
  175.       {
  176.     for (p ++;
  177.          (c = * p)
  178.          && (!c || ! index (string_of_decimal_exponent_marks, c) );
  179.          p ++)
  180.       {
  181.         if (isdigit(c))
  182.           {
  183.         number_of_digits_after_decimal ++; /* This may be retracted below. */
  184.         if (/* seen_significant_digit || */ c > '0')
  185.           {
  186.             seen_significant_digit = TRUE;
  187.           }
  188.           }
  189.         else
  190.           {
  191.         if ( ! seen_significant_digit)
  192.           {
  193.             number_of_digits_after_decimal = 0;
  194.           }
  195.         break;
  196.           }
  197.       }            /* For each digit after decimal mark. */
  198.       }
  199.       while(number_of_digits_after_decimal && first_digit[number_of_digits_before_decimal+number_of_digits_after_decimal]=='0')
  200.     --number_of_digits_after_decimal;
  201. /*    last_digit = p; JF unused */
  202.     
  203.     if (c && index (string_of_decimal_exponent_marks, c) )
  204.       {
  205.     char        digits_exponent_sign_char;
  206.     
  207.     c = * ++ p;
  208.     if (c && index ("+-",c))
  209.       {
  210.         digits_exponent_sign_char = c;
  211.         c = * ++ p;
  212.       }
  213.     else
  214.       {
  215.         digits_exponent_sign_char = '+';
  216.       }
  217.     for (;
  218.          (c);
  219.          c = * ++ p)
  220.       {
  221.         if (isdigit(c))
  222.           {
  223.         decimal_exponent = decimal_exponent * 10 + c - '0';
  224.         /*
  225.          * BUG! If we overflow here, we lose!
  226.          */
  227.           }
  228.         else
  229.           {
  230.         break;
  231.           }
  232.       }
  233.     if (digits_exponent_sign_char == '-')
  234.       {
  235.         decimal_exponent = - decimal_exponent;
  236.       }
  237.       }
  238.     * address_of_string_pointer = p;
  239.   }
  240.  
  241.   number_of_digits_available =
  242.     number_of_digits_before_decimal
  243.       + number_of_digits_after_decimal;
  244.   return_value = 0;
  245.   if (number_of_digits_available == 0)
  246.     {
  247.       address_of_generic_floating_point_number -> exponent = 0;    /* Not strictly necessary */
  248.       address_of_generic_floating_point_number -> leader
  249.     = -1 + address_of_generic_floating_point_number -> low;
  250.       address_of_generic_floating_point_number -> sign = digits_sign_char;
  251.       /* We have just concocted (+/-)0.0E0 */
  252.     }
  253.   else
  254.     {
  255.       LITTLENUM_TYPE *    digits_binary_low;
  256.       int        precision;
  257.       int        maximum_useful_digits;
  258.       int        number_of_digits_to_use;
  259.       int        more_than_enough_bits_for_digits;
  260.       int        more_than_enough_littlenums_for_digits;
  261.       int        size_of_digits_in_littlenums;
  262.       int        size_of_digits_in_chars;
  263.       FLONUM_TYPE    power_of_10_flonum;
  264.       FLONUM_TYPE    digits_flonum;
  265.  
  266.  
  267.       precision = (address_of_generic_floating_point_number -> high
  268.            - address_of_generic_floating_point_number -> low
  269.            + 1
  270.            );        /* Number of destination littlenums. */
  271.                 /* Includes guard bits (two littlenums worth) */
  272.       maximum_useful_digits = (  ((double) (precision - 2))
  273.                    * ((d